package app.vendorportal;

import org.hibernate.cfg.Environment;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.SQLServer2008Dialect;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import javax.inject.Inject;
import javax.persistence.EntityManagerFactory;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.util.Map;

/**
 * @author Bribin
 */
public class DBSchemaExport extends SpringTest {

    private final Logger logger = LoggerFactory.getLogger(DBSchemaExport.class);

    private static final String EXPORTED_SCHEMA_FILE = "build/db-schema-export/db-schema-{DB_TYPE}.sql";

    private LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean;

    @Test
    public void exportSchema() throws Exception {
        EntityManagerFactory nativeEntityManagerFactory = localContainerEntityManagerFactoryBean.getNativeEntityManagerFactory();
        if (nativeEntityManagerFactory instanceof EntityManagerFactoryImpl) {
            EntityManagerFactoryImpl entityManagerFactoryImpl = (EntityManagerFactoryImpl) nativeEntityManagerFactory;

            SessionFactoryImpl sessionFactoryImpl = entityManagerFactoryImpl.getSessionFactory();
            Field schemaExportField = SessionFactoryImpl.class.getDeclaredField("schemaExport");
            schemaExportField.setAccessible(true);
            SchemaExport schemaExport = (SchemaExport) schemaExportField.get(sessionFactoryImpl);
            if (schemaExport != null) {
                String dbType = getDbType();
                String schemaFile = EXPORTED_SCHEMA_FILE.replace("{DB_TYPE}", dbType);
                logger.info("export sql scripts to file: {}", schemaFile);

                schemaExport.setOutputFile(schemaFile);
                schemaExport.setDelimiter(";");
                schemaExport.create(true, false);

                schemaExport.setOutputFile(null);
            } else {
                logger.warn("can't obtain SchemaExport object from SessionFactoryImpl object");
            }
        }
    }

    private String getDbType() {
        JpaVendorAdapter jpaVendorAdapter = localContainerEntityManagerFactoryBean.getJpaVendorAdapter();
        Map<String, ?> jpaPropertyMap = jpaVendorAdapter.getJpaPropertyMap();
        String dialect = jpaPropertyMap.get(Environment.DIALECT).toString();
        String dbType = "db";
        if (HSQLDialect.class.getName().equals(dialect))
            dbType = "hsql";
        else if (MySQL5Dialect.class.getName().equals(dialect))
            dbType = "mysql";
        else if (SQLServer2008Dialect.class.getName().equals(dialect))
            dbType = "mssql";
        return dbType;
    }

    protected void sort(String schemaFile) throws Exception {
        StringBuffer bodyLines = new StringBuffer();
        StringBuffer indexLines = new StringBuffer();

        try (BufferedReader br = new BufferedReader(new FileReader(schemaFile))) {
            String line = br.readLine();
            while (line != null) {
                if (line.startsWith("create index"))
                    indexLines.append(line).append("\r\n");
                else
                    bodyLines.append(line).append("\r\n");
                line = br.readLine();
            }
        }
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(schemaFile))) {
            bw.write(bodyLines.toString());
            bw.write(indexLines.toString());
        }
    }

    @Inject
    public void setLocalContainerEntityManagerFactoryBean(LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean) {
        this.localContainerEntityManagerFactoryBean = localContainerEntityManagerFactoryBean;
    }

}
